using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Fusion
{
	// A better gamepad structure; has button timers, and shorter labels, for convenience
	public struct Controller
	{
		public PlayerIndex index;

		// TODO: change these into PressTimers
		public int A;
		public int B;
		public int X;
		public int Y;

		public int LB;
		public int RB;
		public int LC;
		public int RC;

		public int Left;
		public int Right;
		public int Up;
		public int Down;

		public int Back;
		public int Start;

		public float LT;
		public float RT;
		public int timerLT;
		public int timerRT;

		public Vector2 LS;
		public Vector2 RS;
		public Vector2 YFlipLS
		{ get { return LS * new Vector2( 1, -1 ); } }
		public Vector2 YFlipRS
		{ get { return RS * new Vector2( 1, -1 ); } }
		public bool invertLeftY;
		public bool invertRightY;

		// if the triggers are sadder than this then they count as depressed, and the timers will increase
		public static float TriggerThreshhold = 0.1f;

		public Controller( PlayerIndex Index )
		{
			index = Index;
			A = 0;
			B = 0;
			X = 0;
			Y = 0;

			LB = 0;
			RB = 0;
			LC = 0;
			RC = 0;

			Left = 0;
			Right = 0;
			Up = 0;
			Down = 0;

			Start = 0;
			Back = 0;

			LT = 0;
			RT = 0;
			timerLT = 0;
			timerRT = 0;

			LS = Vector2.Zero;
			RS = Vector2.Zero;
			invertLeftY = false;
			invertRightY = false;
		}

		// Refreshes the buttons
		// Keep in mind this is timed by frames, not by period
		public void Update()
		{
			if( GamePad.GetState( index ).IsButtonDown( Buttons.A ) ) A++; else A = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.B ) ) B++; else B = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.X ) ) X++; else X = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.Y ) ) Y++; else Y = 0;

			if( GamePad.GetState( index ).IsButtonDown( Buttons.LeftShoulder ) ) LB++; else LB = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.RightShoulder ) ) RB++; else RB = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.LeftStick ) ) LC++; else LC = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.RightStick ) ) RC++; else RC = 0;

			if( GamePad.GetState( index ).IsButtonDown( Buttons.DPadLeft ) ) Left++; else Left = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.DPadRight ) ) Right++; else Right = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.DPadUp ) ) Up++; else Up = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.DPadDown ) ) Down++; else Down = 0;

			if( GamePad.GetState( index ).IsButtonDown( Buttons.Back ) ) Back++; else Back = 0;
			if( GamePad.GetState( index ).IsButtonDown( Buttons.Start ) ) Start++; else Start = 0;

			LS = GamePad.GetState( index ).ThumbSticks.Left;
			RS = GamePad.GetState( index ).ThumbSticks.Right;
			if( invertLeftY == true )
				LS *= new Vector2( 1, -1 );
			if( invertRightY == true )
				RS *= new Vector2( 1, -1 );

			LT = GamePad.GetState( index ).Triggers.Left;
			RT = GamePad.GetState( index ).Triggers.Right;
			if( LT > TriggerThreshhold ) timerLT++; else timerLT = 0;
			if( RT > TriggerThreshhold ) timerRT++; else timerRT = 0;
		}

		// Checks if a particular button is pressed
		// Not really nessecary, but might be useful if you want to do (Pad.Held( Buttons.A )) instead of (Pad.A > 0)
		public bool Held( Buttons button )
		{
			if( button == Buttons.A ) return A > 0;
			if( button == Buttons.B ) return B > 0;
			if( button == Buttons.X ) return X > 0;
			if( button == Buttons.Y ) return Y > 0;

			if( button == Buttons.LeftShoulder ) return LB > 0;
			if( button == Buttons.RightShoulder ) return RB > 0;
			if( button == Buttons.LeftStick ) return LC > 0;
			if( button == Buttons.RightStick ) return RC > 0;

			if( button == Buttons.DPadLeft ) return Left > 0;
			if( button == Buttons.DPadRight ) return Right > 0;
			if( button == Buttons.DPadUp ) return Up > 0;
			if( button == Buttons.DPadDown ) return Down > 0;

			if( button == Buttons.Back ) return Back > 0;
			if( button == Buttons.Start ) return Start > 0;

			if( button == Buttons.LeftTrigger ) return RT > TriggerThreshhold;
			if( button == Buttons.RightTrigger ) return LT > TriggerThreshhold;

			return false;
		}
	}

	public class Input
	{
		#region Mouse
		public static Vector2 MouseAbsolute;
		public static Vector2 MousePixel;
		public static int MouseWheel;
		public static bool MouseOnScreen;
		public static int MouseLeft;
		public static int MouseMiddle;
		public static int MouseRight;
		public static int Mouse4;
		public static int Mouse5;

		public static IntDelegate MouseWheeled;
		public static VoidDelegate MouseLeftClicked;
		public static VoidDelegate MouseRightClicked;
		#endregion

		static Dictionary<Keys, int> keyTimers = new Dictionary<Keys, int>();
		public static int Key( Keys key )
		{
			if( keyTimers.ContainsKey( key ) )
				return keyTimers[key];
			else
				return 0;
		}
		public static bool KeyDown( Keys key )
		{
			Keys[] keysDown = Keyboard.GetState().GetPressedKeys();
			for( int i = 0; i < keysDown.Length; i++ )
			{
				if( keysDown[i] == key )
					return true;
			}
			return false;
		}

		public static Controller Pad( PlayerIndex index )
		{
			if( index == PlayerIndex.One ) return Pad1;
			if( index == PlayerIndex.Two ) return Pad2;
			if( index == PlayerIndex.Three ) return Pad3;
			if( index == PlayerIndex.Four ) return Pad4;
			return Pad1;
		}
		public static Controller Pad1 = new Controller( PlayerIndex.One );
		public static Controller Pad2 = new Controller( PlayerIndex.Two );
		public static Controller Pad3 = new Controller( PlayerIndex.Three );
		public static Controller Pad4 = new Controller( PlayerIndex.Four );

		public static void Update()
		{
			// Update Gamepads
			Pad1.Update();
			Pad2.Update();
			Pad3.Update();
			Pad4.Update();

			// Update Keyboard
			Keys[] keysDown = Keyboard.GetState().GetPressedKeys();

			// Increment timers
			foreach( Keys key in keysDown )
				if( keyTimers.ContainsKey( key ) )
					keyTimers[key]++;
				else
					keyTimers[key] = 1;

			// Generate list of keys that aren't pressed and need removing
			List<Keys> removeKeys = new List<Keys>();
			foreach( Keys key in keyTimers.Keys )
				if( keysDown.Contains<Keys>( key ) == false )
					removeKeys.Add( key );

			// and then remove them from the timer dict
			foreach( Keys key in removeKeys )
				keyTimers.Remove( key );



			// Update Mouse
			MouseOnScreen = false;
#if	!XBOX360
			MousePixel.X = Mouse.GetState().X;
			MousePixel.Y = Mouse.GetState().Y;
			MouseAbsolute.X = (float)Mouse.GetState().X / Engine.BufferWidth;
			MouseAbsolute.Y = (float)Mouse.GetState().Y / Engine.BufferHeight;
			if( Mouse.GetState().LeftButton == ButtonState.Pressed ) MouseLeft++; else MouseLeft = 0;
			if( Mouse.GetState().RightButton == ButtonState.Pressed ) MouseRight++; else MouseRight = 0;

			if( MouseLeft == 1 && MouseLeftClicked != null )
				MouseLeftClicked();

			if( MouseRight == 1 && MouseRightClicked != null )
				MouseRightClicked();

#if !SILVERLIGHT
			int nextWheel = Mouse.GetState().ScrollWheelValue;
			if( MouseWheel != nextWheel && MouseWheeled != null )
				MouseWheeled( nextWheel );
			MouseWheel = nextWheel;
			if( Mouse.GetState().MiddleButton == ButtonState.Pressed ) MouseMiddle++; else MouseMiddle = 0;
			if( Mouse.GetState().XButton1 == ButtonState.Pressed ) Mouse4++; else Mouse4 = 0;
			if( Mouse.GetState().XButton2 == ButtonState.Pressed ) Mouse5++; else Mouse5 = 0;
#endif

			if( MousePixel.X >= 0 && MousePixel.Y >= 0 && MousePixel.X <= Engine.BufferWidth && MousePixel.Y <= Engine.BufferHeight )
				MouseOnScreen = true;
#endif
		}
	}
}
